﻿using Trancity;

namespace Common
{
    using Microsoft.DirectX;
    using Microsoft.DirectX.Direct3D;
    using System;
    using System.Drawing;
    using System.Windows.Forms;

    public class MyDirect3D
    {
        public static Double3DPoint Camera_Position;
        public static DoublePoint Camera_Rotation;
        public static Microsoft.DirectX.Direct3D.Font default_font;
        public static Device device;
        public static int load_max = 600;
        public static int load_status = -1;
        public const int players_max = 4;
        public const int players_min = 1;
        public static int progress_color = 0x34ea2;
        public static Microsoft.DirectX.Direct3D.Font splash_font_big;
        public static Microsoft.DirectX.Direct3D.Font splash_font_status;
        public static Texture splash_tex;
        public static string splash_title = "";
        public static Sprite sprite;
        public static string status_string = "";
        public static int viewport_height;
        public static int viewport_width;
        public static int[] viewport_x;
        public static int[] viewport_y;
        public static Texture white_tex;
        public static int Window_Height = 960;
        public static int Window_Width = 0x500;
        public static bool windowed;
        public static bool вид_сверху;
        public static bool карта;
        public static double масштаб = 10.0;

        private static void DrawSplash(int x, int y, int w, int h, int color)
        {
            sprite.Draw2D(splash_tex, new Rectangle(0, 0, Window_Height, Window_Height), new SizeF(Window_Width, Window_Height), new PointF(0, 0), color);
        }

        private static void DrawWhite(int x, int y, int w, int h, int color)
        {
            sprite.Draw2D(white_tex, new Rectangle(0, 0, w, h), new SizeF(w, h), new PointF(x, y), color);
            sprite.Draw2D(white_tex, new Rectangle(0, 0, w, h), new SizeF(w, h), new PointF(x, y), color);
        }

        public static bool Initialize(Control control, DeviceType device_type, CreateFlags create_flags, bool windowed)
        {
            try
            {
                var parameters = new PresentParameters
                                     {
                                         Windowed = false,
                                         FullScreenRefreshRateInHz = 60,
                                         SwapEffect = SwapEffect.Discard,
                                         EnableAutoDepthStencil = true,
                                         AutoDepthStencilFormat = DepthFormat.D16
                                     };
                if ((Window_Width == 0) || (Window_Height == 0))
                {
                    var dialog = new DeviceOptionsDialog("DeviceOptions.xml");
                    if (dialog.windowed)
                    {
                        windowed = true;
                        Window_Width = dialog.windowed_x;
                        Window_Height = dialog.windowed_y;
                    }
                    else
                    {
                        windowed = false;
                        parameters.FullScreenRefreshRateInHz = dialog.fulscreen_rate;
                        Window_Width = dialog.fulscreen_x;
                        Window_Height = dialog.fulscreen_y;
                    }
                }
                MyDirect3D.windowed = windowed;
                if (windowed)
                {
                    if (control is Form)
                    {
                        control.ClientSize = new Size(Window_Width, Window_Height);
                        control.Location = new Point(Screen.PrimaryScreen.WorkingArea.X + ((Screen.PrimaryScreen.WorkingArea.Width - Window_Width) / 2), Screen.PrimaryScreen.WorkingArea.Y + ((Screen.PrimaryScreen.WorkingArea.Height - Window_Height) / 2));
                    }
                    parameters.Windowed = true;
                    parameters.FullScreenRefreshRateInHz = 0;
                    Window_Width = control.ClientSize.Width;
                    Window_Height = control.ClientSize.Height;
                }
                parameters.BackBufferWidth = Window_Width;
                parameters.BackBufferHeight = Window_Height;
                parameters.BackBufferCount = 1;
                parameters.BackBufferFormat = Format.A8R8G8B8;
                parameters.PresentationInterval = PresentInterval.Immediate;
                parameters.DeviceWindow = control;
                device = new Device(0, device_type, control, create_flags, new[] { parameters });
                try
                {
                    var random = new Random();
                    for (var i = 0; i < 11; i += 2)
                    {
                        device.Lights[i].Type = LightType.Directional;
                        var red = 120 + random.Next(11);
                        device.Lights[i].Diffuse = Color.FromArgb(red, red, red);
                        switch (i)
                        {
                            case 0:
                                device.Lights[i].Direction = new Vector3(0f, -1f, 0f);
                                break;

                            case 1:
                                device.Lights[i].Direction = new Vector3(0f, 1f, 0f);
                                break;

                            case 2:
                                device.Lights[i].Direction = new Vector3(1f, 0f, 0f);
                                break;

                            case 3:
                                device.Lights[i].Direction = new Vector3(1f, 0f, 1f);
                                break;

                            case 4:
                                device.Lights[i].Direction = new Vector3(0f, 0f, 1f);
                                break;

                            case 5:
                                device.Lights[i].Direction = new Vector3(-1f, 0f, 1f);
                                break;

                            case 6:
                                device.Lights[i].Direction = new Vector3(-1f, 0f, 0f);
                                break;

                            case 7:
                                device.Lights[i].Direction = new Vector3(-1f, 0f, -1f);
                                break;

                            case 8:
                                device.Lights[i].Direction = new Vector3(0f, 0f, -1f);
                                break;

                            case 9:
                                device.Lights[i].Direction = new Vector3(1f, 0f, -1f);
                                break;

                            case 10:
                                device.Lights[i].Direction = new Vector3(0f, 1f, 0f);
                                break;
                        }
                        device.Lights[i].Enabled = true;
                        device.Lights[i].Update();
                    }
                    device.RenderState.ZBufferEnable = true;
                    device.RenderState.Ambient = Color.White;
                    default_font = new Microsoft.DirectX.Direct3D.Font(device, new System.Drawing.Font("Verdana", 16f));
                    splash_font_big = new Microsoft.DirectX.Direct3D.Font(device, new System.Drawing.Font("Verdana", 80f, FontStyle.Bold));
                    splash_font_status = new Microsoft.DirectX.Direct3D.Font(device, new System.Drawing.Font("Verdana", 30f));
                    sprite = new Sprite(device);
                    try
                    {
                        splash_tex = TextureLoader.FromFile(device, "splash.png");
                    }
                    catch
                    {
                        splash_tex = new Texture(device, 1, 1, 0, Usage.Dynamic, Format.A8R8G8B8, Pool.Default);
                    }
                    try
                    {
                        white_tex = TextureLoader.FromFile(device, "white.bmp");
                    }
                    catch
                    {
                        white_tex = new Texture(device, 1, 1, 0, Usage.Dynamic, Format.A8R8G8B8, Pool.Default);
                    }
                    device.Clear(ClearFlags.ZBuffer | ClearFlags.Target, 0, 1f, 0);
                    device.Present();
                }
                catch
                {
                    MessageBox.Show("Unexpected error occured while creating a device.\nThe created device может работать неправильно.", "Direct3D", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                }
                return true;
            }
            catch (DirectXException)
            {
                return false;
            }
            catch (NullReferenceException exception)
            {
                MessageBox.Show("NullReferenceException\n\n" + exception.ToString());
                return false;
            }
        }

        public static void ResetViewports(int count)
        {
            if (viewport_x == null)
            {
                viewport_x = new int[count];
                viewport_y = new int[count];
                switch (count)
                {
                    case 1:
                        viewport_width = Window_Width;
                        viewport_height = Window_Height;
                        viewport_x[0] = 0;
                        viewport_y[0] = 0;
                        return;

                    case 2:
                        viewport_width = Window_Width;
                        viewport_height = Window_Height / 2;
                        viewport_x[0] = 0;
                        viewport_y[0] = 0;
                        viewport_x[1] = 0;
                        viewport_y[1] = Window_Height / 2;
                        return;

                    case 3:
                        viewport_width = Window_Width / 2;
                        viewport_height = Window_Height / 2;
                        viewport_x[0] = 0;
                        viewport_y[0] = 0;
                        viewport_x[1] = Window_Width / 2;
                        viewport_y[1] = 0;
                        viewport_x[2] = 0;
                        viewport_y[2] = Window_Height / 2;
                        return;

                    case 4:
                        viewport_width = Window_Width / 2;
                        viewport_height = Window_Height / 2;
                        viewport_x[0] = 0;
                        viewport_y[0] = 0;
                        viewport_x[1] = Window_Width / 2;
                        viewport_y[1] = 0;
                        viewport_x[2] = 0;
                        viewport_y[2] = Window_Height / 2;
                        viewport_x[3] = Window_Width / 2;
                        viewport_y[3] = Window_Height / 2;
                        return;
                }
                viewport_width = Window_Width;
                viewport_height = Window_Height;
            }
        }

        public static void SetCameraPos(Double3DPoint position, DoublePoint rotation)
        {
            Camera_Position = position;
            Camera_Rotation = rotation;
            if (!вид_сверху)
            {
                DoublePoint point = new DoublePoint(rotation.x - 1.5707963267948966);
                device.Transform.Projection = (Matrix.Scaling(20f, 20f, 20f) * Matrix.RotationAxis(new Vector3((float)point.x, 0f, (float)point.y), (float)rotation.y)) * Matrix.RotationY((float)rotation.x);
                Transforms transform = device.Transform;
                transform.Projection *= Matrix.LookAtLH(new Vector3(0f, 0f, 0f), new Vector3(1f, 0f, 0f), new Vector3(0f, 1f, 0f));
                Transforms transforms2 = device.Transform;
                transforms2.Projection *= Matrix.PerspectiveLH((4f * viewport_width) / ((float)viewport_height), 4f, 4f, 4000f);
                device.Transform.Projection = Matrix.Translation(-((float)position.x), -((float)position.y), -((float)position.z)) * device.Transform.Projection;
            }
            else
            {
                device.Transform.Projection = Matrix.RotationX(-1.570796f);
                Transforms transforms3 = device.Transform;
                transforms3.Projection *= Matrix.OrthoLH(((float)viewport_width) / ((float)масштаб), ((float)viewport_height) / ((float)масштаб), 0.1f, 100f);
                device.Transform.Projection = Matrix.Translation(-((float)position.x), -50f, -((float)position.z)) * device.Transform.Projection;
            }
        }

        public static void SetViewport(int index)
        {
            Viewport viewport = device.Viewport;
            if (index == -1)
            {
                viewport.Width = Window_Width;
                viewport.Height = Window_Height;
                viewport.X = 0;
                viewport.Y = 0;
                device.Viewport = viewport;
            }
            if (((viewport_x != null) && (viewport_y != null)) && (((index >= 0) && (index < viewport_x.Length)) && (index < viewport_y.Length)))
            {
                viewport.Width = viewport_width - 10;
                viewport.Height = viewport_height - 10;
                viewport.X = viewport_x[index] + 5;
                viewport.Y = viewport_y[index] + 5;
                if (viewport.X == 5)
                {
                    viewport.X = 0;
                    viewport.Width += 5;
                }
                if (viewport.Y == 5)
                {
                    viewport.Y = 0;
                    viewport.Height += 5;
                }
                if ((viewport.X + viewport.Width) == (Window_Width - 5))
                {
                    viewport.Width += 5;
                }
                if ((viewport.Y + viewport.Height) == (Window_Height - 5))
                {
                    viewport.Height += 5;
                }
                device.Viewport = viewport;
            }
        }

        public static void Splash()
        {
            Splash(0xffffff);
        }

        public static void Splash(int color)
        {
            device.Clear(ClearFlags.ZBuffer | ClearFlags.Target, 0, 1f, 0);
            device.BeginScene();
            sprite.Begin(SpriteFlags.None);
            sprite.Draw2D(splash_tex, Rectangle.Empty, new SizeF(Window_Width, Window_Height), new PointF(0, 0), color);
            DrawSplash(0, 0, Window_Width, Window_Height, color);
            Color color2 = Color.FromArgb(0xff, Color.FromArgb(progress_color));
            splash_font_big.DrawText(null, splash_title, new Rectangle(0, 0, Window_Width, 300), DrawTextFormat.VerticalCenter | DrawTextFormat.Center, Color.Black);
            splash_font_status.DrawText(null, status_string, new Rectangle(0, Window_Height - 300, Window_Width, 250), DrawTextFormat.VerticalCenter | DrawTextFormat.Center, color2);
            if (load_status >= 0)
            {
                int h = 5;
                int num2 = 30;
                int x = (Window_Width / 2) - (load_max / 2);
                int y = Window_Height - 100;
                DrawWhite(x - h, y - h, (2 * h) + load_max, h, progress_color);
                DrawWhite(x - h, y + num2, (2 * h) + load_max, h, progress_color);
                DrawWhite(x - h, y, h, num2, progress_color);
                DrawWhite(x + load_max, y, h, num2, progress_color);
                if (load_status > 0)
                {
                    DrawWhite(x, y, load_status, num2, progress_color);
                }
            }
            sprite.End();
            device.EndScene();
            device.Present();
        }

        public static bool Alpha
        {
            get
            {
                return ((device != null) && device.RenderState.AlphaBlendEnable);
            }
            set
            {
                if (device == null) return;
                device.RenderState.AlphaBlendEnable = value;
                //device.RenderState.DiffuseMaterialSource = 
                if (!value) return;
                device.RenderState.SourceBlend = Blend.SourceAlpha;
                device.RenderState.DestinationBlend = Blend.InvSourceAlpha;
            }
        }
    }
}

